/*********************************************************************************
 *      Copyright:  (C) 2022 guoyi<675088383@qq.com>
 *                  All rights reserved.
 *
 *       Filename:  temperature_client.c
 *    Description:  This file 
 *                 
 *        Version:  1.0.0(2022年12月08日)
 *         Author:  guoyi<675088383@qq.com>
 *      ChangeLog:  1, Release initial version on "2022年3月08日 15时41分45秒"
 *                 
 ********************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>
#include <getopt.h>
#include <netdb.h>
#include <fcntl.h>
#include <dirent.h>
#include <time.h>
#include <getopt.h>
#include <signal.h>
#include <netinet/in.h>
#include <syslog.h>
#include <libgen.h>

#include "sqlite3.h"
#include "cjson/cJSON.h"
#include "zlog.h"
#include "conf.h"
#include "common.h"

int g_stop = 0;
zlog_category_t    *zc = NULL;

void sig_handle(int signum);
void get_time(char *datetime, int bytes);
int pack_json(char *json_buf, int bytes, sample_data_t *data);
int socket_report_data(char *json_buf, int bytes, int sockefd);

static inline void print_usage(char *progname)
{
    printf("Usage: %s [OPTIN]...\n", progname);
    printf("-b(--daemon): Let program run in the background.\n");
    printf("-c(--conf): Specify configure file\n");
    printf("-h(--Help): Print this help information.\n");
    return;
}

int main(int argc, char **argv)
{
    int                 rv = -1;
    int                 i, count;
    int                 sockfd = -1;
    int                 daemon_run = 0;
    char                buf[1024];
    char               *progname = NULL;
    int                 opt;
    char               *conf_file = "/home/iot22/guoyi/temperature/etc/all.conf";

    static sqlite3     *db = NULL;
    char               *tb_name = "Temperature";

    time_t              now, start = 0;
    client_ctx_t        conf;
    sample_data_t       data;

    struct option       opts[] =
        {
            {"daemon", no_argument, NULL, 'b'},
            {"conf", no_argument, NULL, 'c'},
            {"help", no_argument, NULL, 'h'},
            {NULL, 0, NULL, 0}
        };

    progname = basename(argv[0]);

    while ((opt = getopt_long(argc, argv, "bch", opts, NULL)) != -1)
    {
        switch (opt)
        {
        case 'b':
            daemon_run = 1;
            break;
        case 'c':
            conf_file = optarg;
            break;
        case 'h':
            print_usage(progname);
            return 0;
        default:
            break;
        }
    }

	
    if( client_parser_conf(conf_file, &conf) < 0 )
    {
        printf("Parser config failure\n");
        return -1;
    }

    strncpy(data.sn, conf.devid, sizeof(data.sn));

	/*日志系统初始化*/
    rv = zlog_init(conf.logconf);
    if( rv )
    {
        printf("zlog_init() failure\n");
        zlog_fini();
        return -2;
    }

    zc = zlog_get_category("my_cat");
    if( !zc )
    {
        printf("zlog_get_category() failure\n");
        zlog_fini();
        return -3;
    }
    printf("Initial zlog successfully\n");

    if( daemon_run == 1 )
    {
        if( (daemon(0, 1)) < 0 )
        {
            printf("Deamon failure : %s\n", strerror(errno));
            goto CleanUp;
        }

        printf("Program %s is running in the background\n", progname);
    }

    if( (db_init(&db, conf.db_name, tb_name)) < 0 )
        goto CleanUp;

    signal(SIGTERM, sig_handle);
    signal(SIGALRM, sig_handle);
    signal(SIGINT, sig_handle);
    signal(SIGPIPE, SIG_IGN);

    while( !g_stop )
    {
        if( sockfd < 0 )
        {
            sockfd = socket_connect(conf.serv_ip, conf.serv_port);
            if( sockfd < 0 )
                log_warn("ERROR: Connect to server failure and will try to connect again!\n\n");
        }
        time(&now);
		/*获取时间间隔*/
        if( (now-start) >= conf.interval )
        {
            start = now;
			/*获取温度*/
            if( get_temperature(&data.temper) < 0)
            {
                log_warn("ERROR: Ds18b20 get temperature failure\n");
                goto NEXT_LOOP;
            }
            memset(data.time, 0, sizeof(data.time));
            get_time(data.time, sizeof(data.time));

            if( sockfd < 0 )
            {
				/*失败存入数据库*/
                db_push_record(db, tb_name, &data, sizeof(data));
                goto NEXT_LOOP;
            }
            memset(buf, 0, sizeof(buf));
            rv = pack_json(buf, sizeof(buf), &data);
            if( socket_report_data(buf, rv, sockfd) < 0 )
            {
                db_push_record(db, tb_name, &data, sizeof(data));
                close(sockfd);
                sockfd = -1;
                goto NEXT_LOOP;
            }
        }
        if( sockfd >= 0 )
        {
            count = db_count_record(db, tb_name);
            if( count <= 0 )
            {
                goto NEXT_LOOP;
            }
            count = (count>10)? 10 : count;

            for( i=0; i<count; i++ )
            {
				/*获取数据*/
                if( db_get_record(db, tb_name, &data, sizeof(data)) < 0 )
                    break;
                memset(buf, 0, sizeof(buf));
                rv = pack_json(buf, sizeof(buf), &data);
                if( socket_report_data(buf, rv, sockfd) < 0 )
                {
                    close(sockfd);
                    sockfd = -1;
                    break;
                }
				/*删除记录*/
                db_del_1stRecord(db, tb_name);
                sleep(1);
            }
        }

NEXT_LOOP:
        sleep(1);
    }

CleanUp:
    close(sockfd);
    db_term(db);
    zlog_fini();
    log_warn("Cleanup completed!\n");
    return 0;
}

/*信号处理函数*/
void sig_handle(int signum)
{
    printf("Catch signal [%d]\n", signum);
    g_stop = 1;
}

/*获取时间函数*/
void get_time(char *datetime, int bytes)
{
    time_t              now;
    struct tm          *t;
    time(&now);
    t = localtime(&now);
    snprintf(datetime, bytes, "%04d-%02d-%02d %02d:%02d:%02d", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, (t->tm_hour)+8, t->tm_min, t->tm_sec);
    return ;
}
/*json格式打包*/
int pack_json(char *json_buf, int bytes, sample_data_t *data)
{
    int                 rv = 0;
    char                temper_str[32] = {0};
    cJSON              *sn = NULL;
    cJSON              *time = NULL;
    cJSON              *temper = NULL;
    cJSON              *json = NULL;

    if( !json_buf || !data )
    {
        log_warn("ERROR: Invalid input arguments\n");
        return -1;
    }

    if( NULL == (json = cJSON_CreateObject()) )
    {
        log_warn("cJSON_CreateObject() failure\n");
        return -2;
    }

    sn = cJSON_CreateString(data->sn);
    time = cJSON_CreateString(data->time);
    snprintf(temper_str, sizeof(temper_str), "%.3f℃", (data->temper));
    temper = cJSON_CreateString(temper_str);

    if( !sn || !time || !temper )
    {
        log_warn("cJSON_AddItemToObject() failure\n");
        rv = -3;
        goto OUT;
    }
    cJSON_AddItemToObject(json, "sn", sn);
    cJSON_AddItemToObject(json, "datetime", time);
    cJSON_AddItemToObject(json, "temper", temper);
    strncpy(json_buf, cJSON_Print(json), bytes);
    rv = strlen(json_buf);

OUT:
    cJSON_Delete(json);

    return rv;
}
/*数据发送*/
int socket_report_data(char *json_buf, int bytes, int sockfd)
{
    if( !json_buf || !sockfd )
    {
        log_warn("ERROR: Invalid input arguments\n");
        return -1;
    }

    if( write(sockfd ,json_buf, bytes) < 0 )
    {
        log_warn("ERROR: Report temperature packet from socket[%d] failure\n", sockfd);
        return -2;
    }   
    log_debug("Report temperature packet from socket[%d] successfully!\n", sockfd);

    return 0;
}
